"""step5_3_prepare_d_view

目的：
    在物理 FEE 表上追加并填充需要的融合 / 计算列（来自 MDTRT / SETL / 派生逻辑），随后创建视图 d。
    视图 m 只展示 j_drop IS NULL 的有效数据（无效行 j_drop='1' 不出现在视图中），并按 env_structure.xlsx 中的别名(core) 输出列名。
    不做字典汉化 / _MAP 字段。
    不生成 j_refund；保留 j_rand；j_drop= '1' 表示无效，正常为 NULL。

步骤概要：
    1. 读取 env_structure.xlsx (获取 SETL / MDTRT / FEE 字段列表及 core 别名)。注意：全都转换为大写
    2. 对 DX 表，增加一列 DX_NAME，关联 STABLE_ICD10 表，通过 DX_CODE 关联 DX 获取 DXNAME 名称；增加一列 DX_J_CODE
    3. 对 TX 表，增加一列 TX_NAME，关联 STABLE_ICD9 表，通过 TX_CODE 关联 TX 获取 TXNAME 名称；增加一列 TX_J_CODE
    4. 创建索引：
        4.1. DX 表创建 SETL_ID, DX_CODE
        4.2. TX 表创建 SETL_ID, TX_CODE
    5. 创建视图 dx, tx
运行：
   python STEP5干净表/step5_4_prepare_icd_view.py
"""
from __future__ import annotations
import os
import sys
from pathlib import Path
from typing import List, Dict
import argparse
import pandas as pd
from sqlalchemy import text
from sqlalchemy.engine import Engine
import time

ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))
if ROOT_DIR not in sys.path:
    sys.path.append(ROOT_DIR)

from config import create_db_engine, load_env_tbl_name

# 元数据文件与环境变量键名常量
STRUCTURE_FILE = 'ENV.xlsx'
STRUCTURE_SHEET = 'env_structure'

# 获得所有表名的环境变量键名
SETL_TBL_NAME, MDTRT_TBL_NAME, FEE_TBL_NAME, DX_TBL_NAME, TX_TBL_NAME = load_env_tbl_name()

SETL_ENV = SETL_TBL_NAME
DX_ENV = DX_TBL_NAME
TX_ENV = TX_TBL_NAME


# 时间函数
t0 = time.time()
def elapsed() -> str:
    """返回自脚本启动以来的耗时 (HH:MM:SS)。
    用于将原先的 [INFO]/[START]/[DONE] 等等级标签替换成实时耗时。
    """
    
    # 实际时间，yyy-mm-dd hh:mm:ss
    timeStr = time.strftime("%H:%M:%S", time.localtime())
    
    # 已消耗时间 XX hours XX minutes XX.XX seconds
    delta = int(time.time() - t0)
    if delta < 60:
        return f"{timeStr} (+ {delta} sec)"
    elif delta < 3600:
        m, s = divmod(delta, 60)
        return f"{timeStr} (+ {m} min {s} sec)"
    elif delta < 86400:
        h, rem = divmod(delta, 3600)
        m, s = divmod(rem, 60)
        return f"{timeStr} (+ {h} hour {m} min {s} sec)"
    else:
        d, rem = divmod(delta, 86400)
        h, rem = divmod(rem, 3600)
        m, s = divmod(rem, 60)
        return f"{timeStr} (+ {d} day {h} hour {m} min {s} sec)"

# ------------------------------
#  读取配置与环境
# ------------------------------
def read_env_structure(file_path: str = STRUCTURE_FILE) -> pd.DataFrame:
    # 读取 env_structure.xlsx，返回 DataFrame
    df_raw = pd.read_excel(file_path, sheet_name=STRUCTURE_SHEET)
    needed = ['tbl_name', 'field_code', 'field_name', 'core']
    for c in needed:
            if c not in df_raw.columns:
                    raise ValueError(f'env_structure.xlsx 缺少列: {c}')

    df = df_raw[needed].copy()
    # 标准化
    df['tbl_name'] = df['tbl_name'].astype(str).str.strip().str.upper()
    df['field_code'] = df['field_code'].astype(str).str.strip().str.upper()
    df['core'] = df['core'].fillna('').astype(str).str.strip().str.upper()
    df['field_name'] = df['field_name'].fillna('').astype(str).str.strip()
    print(f"[{elapsed()}] 读取结构表，行数={len(df)}")
    return df

def resolve_table_names() -> tuple[str, str, str]:
    # 读取环境变量中的核心表名 SETL, MDTRT, FEE
    setl = SETL_TBL_NAME
    dx = DX_TBL_NAME
    tx = TX_TBL_NAME
    print(f"[{elapsed()}] 解析环境变量: {SETL_ENV}={setl}, {DX_ENV}={dx}, {TX_ENV}={tx}")
    return setl, dx, tx

def resolve_cores(struct_df: pd.DataFrame, tbl_name: str) -> Dict[str, str]:
    # 从结构表中解析指定表的 core -> field_code 映射
    df = struct_df[struct_df['tbl_name'] == tbl_name.upper()]
    core_map = {}
    for _, row in df.iterrows():
        core = row['core']
        field_code = row['field_code']
        if core:
            core_map[core] = field_code
    print(f"[{elapsed()}] 解析 {tbl_name} 核心列映射，共 {len(core_map)} 列")
    return core_map

def _column_exists(engine: Engine, table: str, col: str) -> bool:
    sql = text("SELECT 1 FROM user_tab_columns WHERE table_name=:t AND column_name=:c")
    with engine.begin() as conn:
        return conn.execute(sql, {'t': table.upper(), 'c': col.upper()}).fetchone() is not None

def _get_column_meta(engine: Engine, table: str, col: str) -> tuple[str | None, int | None]:
    sql = text(
        """
        SELECT data_type, data_length
        FROM user_tab_columns
        WHERE table_name=:t AND column_name=:c
        """
    )
    with engine.begin() as conn:
        row = conn.execute(sql, {'t': table.upper(), 'c': col.upper()}).fetchone()
    if row is None:
        return None, None
    return row[0], row[1]

def _add_column(engine: Engine, table: str, col: str, dtype: str):
    ddl = f"ALTER TABLE {table} ADD ({col} {dtype})"
    with engine.begin() as conn:
        try:
            conn.execute(text(ddl))
        except Exception as e:
            msg = str(e)
            # ORA-01430: column being added already exists in table / ORA-00955 object already exists
            if 'ORA-01430' in msg or 'already exists' in msg or 'ORA-00955' in msg:
                print(f"[{elapsed()}] {col} 已存在 (SKIP)")
            else:
                raise

def _index_exists(engine: Engine, index_name: str) -> bool:
    sql = text("SELECT 1 FROM user_indexes WHERE index_name = :n")
    with engine.begin() as conn:
        return conn.execute(sql, { 'n': index_name.upper() }).fetchone() is not None

# ------------------------------
# 增加 ICD_NAME 列
# ------------------------------
def add_dx_dx_name(engine: Engine, dxTblName: str, dxCoresMap: Dict[str, str]):
    """为 DX 表增加 DXNAME 列，关联 STABLE_ICD10 表"""
    print(f"[{elapsed()}] 为 {dxTblName} 增加 DX_NAME 列...")
    with engine.connect() as conn:
        # 检查并添加列
        if not _column_exists(engine, dxTblName, 'DX_NAME'):
            _add_column(engine, dxTblName, 'DX_NAME', 'VARCHAR2(1000)')
            print(f"[{elapsed()}] 列 DX_NAME 已添加到 {dxTblName}")
        else:
            print(f"[{elapsed()}] 列 DX_NAME 已存在于 {dxTblName}")

        # 获得 dx_setlId 的 field_code
        dx_dxCode = dxCoresMap['DX_CODE']

        # 更新 DX_NAME 列
        update_sql = f"""
        MERGE INTO {dxTblName}
        USING STABLE_ICD10 icd
        ON (LOWER({dxTblName}.{dx_dxCode}) = LOWER(icd.DX))
        WHEN MATCHED THEN
            UPDATE SET {dxTblName}.DX_NAME = icd.DXNAME
        """
        result = conn.execute(text(update_sql))
        conn.commit()
        print(f"[{elapsed()}] {dxTblName} 的 DX_NAME 列已更新，共影响行数: {result.rowcount}")

def add_dx_j_code(engine: Engine, dxTblName: str, dxCoresMap: Dict[str, str]):
    """为 DX 表增加 DX_J_CODE 列"""
    print(f"[{elapsed()}] 为 {dxTblName} 增加 DX_J_CODE 列...")
    str_col = 'DX_J_CODE_STR'
    num_col = 'DX_J_CODE'

    # 确保字符串列存在
    str_type, _ = _get_column_meta(engine, dxTblName, str_col)
    if str_type is None:
        _add_column(engine, dxTblName, str_col, 'VARCHAR2(1000)')
        print(f"[{elapsed()}] 列 {dxTblName}.{str_col} 已创建")
    elif str_type.upper() not in ('VARCHAR2', 'NVARCHAR2'):
        with engine.begin() as conn:
            conn.execute(text(f"ALTER TABLE {dxTblName} DROP COLUMN {str_col}"))
        _add_column(engine, dxTblName, str_col, 'VARCHAR2(1000)')
        print(f"[{elapsed()}] 列 {dxTblName}.{str_col} 已重新创建为 VARCHAR2")

    # 确保数字列为 NUMBER
    num_type, _ = _get_column_meta(engine, dxTblName, num_col)
    if num_type is not None and num_type.upper() != 'NUMBER':
        with engine.begin() as conn:
            conn.execute(text(f"ALTER TABLE {dxTblName} DROP COLUMN {num_col}"))
        num_type = None
    if num_type is None:
        _add_column(engine, dxTblName, num_col, 'NUMBER')
        print(f"[{elapsed()}] 列 {dxTblName}.{num_col} 已创建为 NUMBER")

    dx_dxCode = dxCoresMap['DX_CODE']
    dx_dxHspName = dxCoresMap['DX_HSP_NAME']
    dx_name_expr = "NVL(DX_NAME,'')" if _column_exists(engine, dxTblName, 'DX_NAME') else "''"
    string_expr = (
        "SUBSTR("
        "REPLACE("
        f"NVL({dx_dxCode},'') || '|' || NVL({dx_dxHspName},'') || '|' || {dx_name_expr}"
        ", '''''', '_')"
        ", 1, 1000)"
    )

    with engine.begin() as conn:
        update_sql = text(f"""
            UPDATE {dxTblName}
            SET {str_col} = {string_expr}
        """)
        result = conn.execute(update_sql)
        print(f"[{elapsed()}] {dxTblName}.{str_col} 已更新，共影响行数: {result.rowcount}")

def add_tx_tx_name(engine: Engine, txTblName: str, txCoresMap: Dict[str, str]):
    """为 TX 表增加 TX_NAME 列，关联 STABLE_ICD9 表"""
    print(f"[{elapsed()}] 为 {txTblName} 增加 TX_NAME 列...")
    with engine.connect() as conn:
        # 检查并添加列
        if not _column_exists(engine, txTblName, 'TX_NAME'):
            _add_column(engine, txTblName, 'TX_NAME', 'VARCHAR2(1000)')
            conn.commit()
            print(f"[{elapsed()}] 列 TX_NAME 已添加到 {txTblName}")
        else:
            print(f"[{elapsed()}] 列 TX_NAME 已存在于 {txTblName}")

        # 获得 tx_setlId 的 field_code
        tx_txCode = txCoresMap['TX_CODE']

        # 更新 TX_NAME 列
        update_sql = f"""
        MERGE INTO {txTblName}
        USING STABLE_ICD9 icd
        ON (LOWER({txTblName}.{tx_txCode}) = LOWER(icd.TX))
        WHEN MATCHED THEN
            UPDATE SET {txTblName}.TX_NAME = icd.TXNAME
        """
        result = conn.execute(text(update_sql))
        conn.commit()
        print(f"[{elapsed()}] {txTblName} 的 TX_NAME 列已更新，共影响行数: {result.rowcount}")

def add_tx_j_code(engine: Engine, txTblName: str, txCoresMap: Dict[str, str]):
    """为 TX 表增加 TX_J_CODE 列"""
    print(f"[{elapsed()}] 为 {txTblName} 增加 TX_J_CODE 列...")
    str_col = 'TX_J_CODE_STR'
    num_col = 'TX_J_CODE'

    str_type, _ = _get_column_meta(engine, txTblName, str_col)
    if str_type is None:
        _add_column(engine, txTblName, str_col, 'VARCHAR2(1000)')
        print(f"[{elapsed()}] 列 {txTblName}.{str_col} 已创建")
    elif str_type.upper() not in ('VARCHAR2', 'NVARCHAR2'):
        with engine.begin() as conn:
            conn.execute(text(f"ALTER TABLE {txTblName} DROP COLUMN {str_col}"))
        _add_column(engine, txTblName, str_col, 'VARCHAR2(1000)')
        print(f"[{elapsed()}] 列 {txTblName}.{str_col} 已重新创建为 VARCHAR2")

    num_type, _ = _get_column_meta(engine, txTblName, num_col)
    if num_type is not None and num_type.upper() != 'NUMBER':
        with engine.begin() as conn:
            conn.execute(text(f"ALTER TABLE {txTblName} DROP COLUMN {num_col}"))
        num_type = None
    if num_type is None:
        _add_column(engine, txTblName, num_col, 'NUMBER')
        print(f"[{elapsed()}] 列 {txTblName}.{num_col} 已创建为 NUMBER")

    tx_txCode = txCoresMap['TX_CODE']
    tx_txHspName = txCoresMap['TX_HSP_NAME']
    tx_name_expr = "NVL(TX_NAME,'')" if _column_exists(engine, txTblName, 'TX_NAME') else "''"
    string_expr = (
        "SUBSTR("
        "REPLACE("
        f"NVL({tx_txCode},'') || '|' || NVL({tx_txHspName},'') || '|' || {tx_name_expr}"
        ", '''''', '_')"
        ", 1, 1000)"
    )

    with engine.begin() as conn:
        update_sql = text(f"""
            UPDATE {txTblName}
            SET {str_col} = {string_expr}
        """)
        result = conn.execute(update_sql)
        print(f"[{elapsed()}] {txTblName}.{str_col} 已更新，共影响行数: {result.rowcount}")


def _update_joint_numeric_code(engine: Engine, targets: List[Dict[str, str]]):
    """为多个表统一生成 J_CODE 数值，确保跨表唯一。"""

    if not targets:
        return

    tmp_tbl = 'TMP_JCODES'
    pk_name = 'PK_TMP_JCODES'
    idx_name = 'IDX_TMP_JCODES'

    with engine.begin() as conn:
        conn.execute(text(
            f"""
            BEGIN
                EXECUTE IMMEDIATE 'DROP TABLE {tmp_tbl} PURGE';
            EXCEPTION
                WHEN OTHERS THEN NULL;
            END;
            """
        ))

    union_parts = []
    for item in targets:
        tbl = item['table']
        str_col = item['str_col']
        union_parts.append(
            f"SELECT DISTINCT {str_col} AS str_val FROM {tbl} WHERE {str_col} IS NOT NULL"
        )
    union_sql = " UNION ".join(union_parts)

    create_tmp_sql = text(
        f"""
        CREATE TABLE {tmp_tbl}
        NOLOGGING
        AS
        SELECT str_val,
               ROW_NUMBER() OVER (ORDER BY str_val) AS code_val
        FROM (
            {union_sql}
        )
        """
    )
    with engine.begin() as conn:
        conn.execute(create_tmp_sql)

    with engine.begin() as conn:
        conn.execute(text(
            f"""
            ALTER TABLE {tmp_tbl}
                ADD CONSTRAINT {pk_name} PRIMARY KEY (code_val)
            """
        ))

    with engine.begin() as conn:
        conn.execute(text(
            f"""
            CREATE UNIQUE INDEX {idx_name} ON {tmp_tbl} (str_val)
            """
        ))

    for item in targets:
        tbl = item['table']
        str_col = item['str_col']
        num_col = item['num_col']
        merge_sql = text(
            f"""
            MERGE INTO {tbl} tgt
            USING {tmp_tbl} src
            ON (tgt.{str_col} = src.str_val)
            WHEN MATCHED THEN UPDATE SET tgt.{num_col} = src.code_val
            """
        )
        with engine.begin() as conn:
            result = conn.execute(merge_sql)
            print(f"[{elapsed()}] {tbl}.{num_col} 数字编码更新完成，更新行数: {result.rowcount}")

    with engine.begin() as conn:
        conn.execute(text(f"DROP TABLE {tmp_tbl} PURGE"))


def update_joint_j_codes(engine: Engine, dxTblName: str, txTblName: str):
    """同步 DX/TX 的 J_CODE 数值，避免重复。"""

    targets: List[Dict[str, str]] = []
    if _column_exists(engine, dxTblName, 'DX_J_CODE_STR') and _column_exists(engine, dxTblName, 'DX_J_CODE'):
        targets.append({'table': dxTblName, 'str_col': 'DX_J_CODE_STR', 'num_col': 'DX_J_CODE'})
    if _column_exists(engine, txTblName, 'TX_J_CODE_STR') and _column_exists(engine, txTblName, 'TX_J_CODE'):
        targets.append({'table': txTblName, 'str_col': 'TX_J_CODE_STR', 'num_col': 'TX_J_CODE'})
    if not targets:
        print(f"[{elapsed()}] 未发现可同步的 J_CODE 列，跳过联合编码。")
        return
    _update_joint_numeric_code(engine, targets)

# ------------------------------
#  创建索引
# ------------------------------
def create_dx_index(engine: Engine, dxTblName: str, dxCoresMap: Dict[str, str]):
    """为 DX 表创建索引"""
    print(f"[{elapsed()}] 为 {dxTblName} 创建索引...")
    with engine.connect() as conn:
        dx_setlId = dxCoresMap['SETL_ID']
        dx_code = dxCoresMap['DX_CODE']
        index_name = f"idx_{dxTblName.lower()}_setl_dx"
        # 如果索引已存在，直接跳过
        if _index_exists(engine, index_name):
            print(f"[{elapsed()}] 索引 {index_name} 已存在，跳过创建")
            return
        # 过程创建索引，忽略 ORA-01408（已存在相同列组合）与 ORA-00955（名称已被使用）
        sql = text(f"""
            BEGIN
                EXECUTE IMMEDIATE 'CREATE INDEX {index_name} ON {dxTblName} ({dx_setlId}, {dx_code})';
            EXCEPTION
                WHEN OTHERS THEN
                    IF SQLCODE IN (-1408, -955) THEN
                        NULL; -- 忽略索引已存在或名称已被使用
                    ELSE
                        RAISE;
                    END IF;
            END;
        """)
        with engine.begin() as conn:
            conn.execute(sql)
            print(f"[{elapsed()}] 索引 {index_name} 创建完成（或已存在）")

def create_tx_index(engine: Engine, txTblName: str, txCoresMap: Dict[str, str]):
    """为 TX 表创建索引"""
    print(f"[{elapsed()}] 为 {txTblName} 创建索引...")
    with engine.connect() as conn:
        tx_setlId = txCoresMap['SETL_ID']
        tx_code = txCoresMap['TX_CODE']
        index_name = f"idx_{txTblName.lower()}_setl_tx"
        # 如果索引已存在，直接跳过
        if _index_exists(engine, index_name):
            print(f"[{elapsed()}] 索引 {index_name} 已存在，跳过创建")
            return
        # 过程创建索引，忽略 ORA-01408（已存在相同列组合）与 ORA-00955（名称已被使用）
        sql = text(f"""
            BEGIN
                EXECUTE IMMEDIATE 'CREATE INDEX {index_name} ON {txTblName} ({tx_setlId}, {tx_code})';
            EXCEPTION
                WHEN OTHERS THEN
                    IF SQLCODE IN (-1408, -955) THEN
                        NULL; -- 忽略索引已存在或名称已被使用
                    ELSE
                        RAISE;
                    END IF;
            END;
        """)
        with engine.begin() as conn:
            conn.execute(sql)
            print(f"[{elapsed()}] 索引 {index_name} 创建完成（或已存在）")

# ------------------------------
#  创建视图
# ------------------------------
def create_dx_view(
        engine: Engine, 
        dxTblName: str, setlTblName: str,
        dxCoresMap: Dict[str, str], setlCoresMap: Dict[str, str]
):
    """创建 DX 视图"""
    # 视图中需要的列，分别是 表、字段、别名
    needed_fields = [
        ('dx', dxCoresMap['SETL_ID'], 'SETL_ID'),
        ('dx', dxCoresMap['DX_CODE'], 'DX_CODE'),
        ('dx', 'DX_NAME', 'DX_NAME'),
        ('dx', 'DX_J_CODE_STR', 'DX_J_CODE_STR'),
        ('dx', 'DX_J_CODE', 'DX_J_CODE'),
        ('setl', setlCoresMap['PSN_NO'], 'PSN_NO'),
        ('setl', 'HSP_ABBR', 'HSP_ABBR'),
        ('dx', dxCoresMap['IS_MAIN'], 'IS_MAIN'),
        ('dx', dxCoresMap['DX_HSP_NAME'], 'DX_HSP_NAME'),
    ]
    selectSql = ',\n            '.join(
        [f"{tbl}.{field} AS {alias}" for tbl, field, alias in needed_fields]
    )
    with engine.connect() as conn:
        # 创建新视图
        create_sql = text(f"""
        CREATE OR REPLACE VIEW DX AS
        SELECT
            {selectSql}
        FROM {dxTblName} dx, {setlTblName} setl
        WHERE dx.{dxCoresMap['SETL_ID']} = setl.{setlCoresMap['SETL_ID']}
            AND setl.{setlCoresMap['VALI_FLAG']} = '1'
            AND dx.{dxCoresMap['VALI_FLAG']} = '1'
        """)
        conn.execute(create_sql)
        conn.commit()
        print(f"[{elapsed()}] 视图 DX 已创建")

def create_tx_view(
        engine: Engine,
        txTblName: str, setlTblName: str,
        txCoresMap: Dict[str, str], setlCoresMap: Dict[str, str]
):
    """创建 TX 视图"""
    # 视图中需要的列，分别是 表、字段、别名
    needed_fields = [
        ('tx', txCoresMap['SETL_ID'], 'SETL_ID'),
        ('tx', txCoresMap['TX_CODE'], 'TX_CODE'),
        ('tx', 'TX_NAME', 'TX_NAME'),
        ('tx', 'TX_J_CODE_STR', 'TX_J_CODE_STR'),
        ('tx', 'TX_J_CODE', 'TX_J_CODE'),
        ('setl', setlCoresMap['PSN_NO'], 'PSN_NO'),
        ('setl', 'HSP_ABBR', 'HSP_ABBR'),
        ('tx', txCoresMap['IS_MAIN'], 'IS_MAIN'),
        ('tx', txCoresMap['TX_HSP_NAME'], 'TX_HSP_NAME'),
    ]
    selectSql = ',\n            '.join(
        [f"{tbl}.{field} AS {alias}" for tbl, field, alias in needed_fields]
    )
    with engine.connect() as conn:
        # 创建新视图
        create_sql = text(f"""
        CREATE OR REPLACE VIEW TX AS
        SELECT
            {selectSql}
        FROM {txTblName} tx, {setlTblName} setl
        WHERE tx.{txCoresMap['SETL_ID']} = setl.{setlCoresMap['SETL_ID']}
            AND setl.{setlCoresMap['VALI_FLAG']} = '1'
            AND tx.{txCoresMap['VALI_FLAG']} = '1'
        """)
        conn.execute(create_sql)
        conn.commit()
        print(f"[{elapsed()}] 视图 TX 已创建")

# ------------------------------
#  主流程
# ------------------------------
def main():
    parser = argparse.ArgumentParser(description='step5_3_prepare_d_view: 可从指定步骤开始执行')
    parser.add_argument('-s', '--start-step', type=int, default=3, choices=[3,4,5,6,7], help='从第几步开始执行 (3-7)')
    args = parser.parse_args()
    start_step = args.start_step

    # 读取配置与环境
    struct_df = read_env_structure(STRUCTURE_FILE)
    setl, dx, tx = resolve_table_names()
    setlCoresMap = resolve_cores(struct_df, 'SETL')
    dxCoresMap = resolve_cores(struct_df, 'DX')
    txCoresMap = resolve_cores(struct_df, 'TX')

    # 创建数据库连接
    engine = create_db_engine()

    print(f"[{elapsed()}] 从第 {start_step} 步开始执行")

    # 步骤 3: 为 DX 表增加 DX_NAME 列、DX_J_CODE 列
    if start_step <= 3:
        add_dx_dx_name(engine, dx, dxCoresMap)
        add_dx_j_code(engine, dx, dxCoresMap)
    
    # 步骤 4: 为 TX 表增加 DX_NAME 列、TX_J_CODE 列
    if start_step <= 4:
        add_tx_tx_name(engine, tx, txCoresMap)
        add_tx_j_code(engine, tx, txCoresMap)
    
    update_joint_j_codes(engine, dx, tx)

    # 步骤 5: 为 DX 表创建索引
    if start_step <= 5:
        create_dx_index(engine, dx, dxCoresMap)
    
    # 步骤 6: 为 TX 表创建索引
    if start_step <= 6:
        create_tx_index(engine, tx, txCoresMap)
    
    # 步骤 7: 创建 DX 视图
    if start_step <= 7:
        create_dx_view(engine, dx, setl, dxCoresMap, setlCoresMap)
        create_tx_view(engine, tx, setl, txCoresMap, setlCoresMap)

if __name__ == '__main__':
    main()
    print(f'[{elapsed()}] 主流程完成') 